package com.ibeeking.gmc.global.g.rest.service.impl;

import com.ibeeking.gmc.global.g.rest.service.ITenantDataAuthService;
import com.ibeeking.gmc.global.g.rest.service.ITenantService;
import com.ibeeking.found.common.base.BaseDO;
import com.ibeeking.found.common.entity.CurrentUser;
import com.ibeeking.gmc.global.api.common.param.ApprovalDataAuthParam;
import com.ibeeking.gmc.global.api.common.param.TenantDataAuthParam;
import com.ibeeking.gmc.global.service.common.constants.enums.TenantDataAuthEnum;
import com.ibeeking.gmc.global.service.common.dos.TenantAuthDO;
import com.ibeeking.gmc.global.service.common.dos.TenantAuthRecordDO;
import com.ibeeking.gmc.global.service.common.query.TenantEffectiveQuery;
import com.ibeeking.gmc.global.service.common.vo.TenantDataAuthVO;
import com.ibeeking.gmc.global.service.common.vo.TenantEffectiveVO;
import com.ibeeking.gmc.global.service.mapper.TenantAuthMapper;
import com.ibeeking.gmc.global.service.mapper.TenantAuthRecordMapper;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.redis.utils.RedisUtils;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName TenantDataAuthServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-05-21 9:48
 **/
@Service
public class TenantDataAuthServiceImpl implements ITenantDataAuthService {

    private static final String DATA_AUTH_LOCK = "DATA_AUTH_LOCK";

    @Resource
    private RedisUtils redisUtils;
    @Resource
    private TenantAuthMapper tenantAuthMapper;
    @Resource
    private TenantAuthRecordMapper tenantAuthRecordMapper;
    @Resource
    private ITenantService ITenantServiceImpl;

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean applyAuth(CurrentUser currentUser, TenantDataAuthParam param) {
        TenantAuthDO tenantAuthDO = null;
        try {
            if (redisUtils.tryLock(DATA_AUTH_LOCK + currentUser.getTenantId())) {
                //查询是否存在授权历史
                tenantAuthDO = tenantAuthMapper.selectOne(new LambdaQueryWrapper<>(TenantAuthDO.class)
                        .eq(TenantAuthDO::getTenantId, currentUser.getTenantId())
                        .eq(TenantAuthDO::getTargetTenantId, param.getTargetTenantId())
                );
                if (null == tenantAuthDO) {
                    tenantAuthDO = new TenantAuthDO();
                }
                tenantAuthDO.setTenantId(currentUser.getTenantId());
                tenantAuthDO.setTargetTenantId(param.getTargetTenantId());
                tenantAuthDO.setAuthScope(param.getAuthScope());
                tenantAuthDO.setStatus(TenantDataAuthEnum.APPLYING.getValue());
                tenantAuthDO.setCreateBy(currentUser.getId());
                tenantAuthDO.setModifyTime(LocalDateTime.now());
                if (null == tenantAuthDO.getId()) {
                    tenantAuthDO.setCreateTime(LocalDateTime.now());
                    tenantAuthMapper.insert(tenantAuthDO);
                } else {
                    tenantAuthMapper.updateById(tenantAuthDO);
                }
            }
        } finally {
            redisUtils.unlock(DATA_AUTH_LOCK + currentUser.getTenantId());
        }
        TenantAuthRecordDO tenantAuthRecordDO = new TenantAuthRecordDO();
        tenantAuthRecordDO.setAuthId(tenantAuthDO.getId());
        tenantAuthRecordDO.setApplicant(currentUser.getId());
        tenantAuthRecordDO.setApplicantName(currentUser.getName());
        tenantAuthRecordDO.setApplicantReason(param.getApplyReason());
        tenantAuthRecordDO.setTargetStatus(TenantDataAuthEnum.APPLYING.getValue());
        tenantAuthRecordDO.setCreateTime(LocalDateTime.now());

        tenantAuthRecordMapper.insert(tenantAuthRecordDO);
        return true;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean approvalAuth(CurrentUser currentUser, ApprovalDataAuthParam param) {
        TenantAuthDO tenantAuthDO = tenantAuthMapper.selectById(param.getId());
        if (!TenantDataAuthEnum.APPLYING.getValue().equals(tenantAuthDO.getStatus())) {
            throw new BusinessException("非申请状态，无法审批");
        }
        modify(currentUser, tenantAuthDO.getStatus(), param.getStatus(), param);
        return true;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean stopAuth(CurrentUser currentUser, ApprovalDataAuthParam param) {
        TenantAuthDO tenantAuthDO = tenantAuthMapper.selectById(param.getId());
        modify(currentUser, tenantAuthDO.getStatus(), TenantDataAuthEnum.STOP.getValue(), param);
        return true;
    }

    @Override
    public List<TenantDataAuthVO> listDataAuth(CurrentUser currentUser) {
        List<TenantAuthDO> tenantAuthDos = tenantAuthMapper.selectList(new LambdaQueryWrapper<>(TenantAuthDO.class)
                .orderByDesc(BaseDO::getCreateTime)
                .eq(TenantAuthDO::getTenantId, currentUser.getTenantId())
        );
        if (Collections3.isEmpty(tenantAuthDos)) {
            return Collections3.emptyList();
        }
        Map<Integer, TenantAuthDO> tenantMap = tenantAuthDos.stream().collect(Collectors.toMap(TenantAuthDO::getTargetTenantId, s -> s, (s, a) -> s));

        TenantEffectiveQuery query = new TenantEffectiveQuery();
        query.setIds(new ArrayList<>(tenantMap.keySet()));
        List<TenantEffectiveVO> tenantEffectiveVos = ITenantServiceImpl.effectiveList(query);
        List<TenantDataAuthVO> result = JsonUtils.jsonToList(tenantEffectiveVos, TenantDataAuthVO.class);
        result.stream().forEach(s -> {
            s.setTenantId(Integer.valueOf(String.valueOf(s.getId())));
            s.setId(tenantMap.get(s.getTenantId()).getId());
            s.setAuthScope(tenantMap.get(s.getTenantId()).getAuthScope());
            s.setAuthScopeName(1 == tenantMap.get(s.getTenantId()).getAuthScope() ? "全部" : "部分");
            s.setStatus(tenantMap.get(s.getTenantId()).getStatus());
            s.setStatusName(TenantDataAuthEnum.getName(tenantMap.get(s.getTenantId()).getStatus()));
        });
        return result;
    }

    @Override
    public List<Integer> listTenantId(CurrentUser currentUser) {
        List<TenantAuthDO> tenantAuthDos = tenantAuthMapper.selectList(new LambdaQueryWrapper<>(TenantAuthDO.class)
                .orderByDesc(BaseDO::getCreateTime)
                .eq(TenantAuthDO::getStatus, TenantDataAuthEnum.AGREE.getValue())
                .eq(TenantAuthDO::getTenantId, currentUser.getTenantId())
        );
        return tenantAuthDos.stream().distinct().map(TenantAuthDO::getTargetTenantId).collect(Collectors.toList());
    }

    private void modify(CurrentUser currentUser, Integer currentStatus, Integer targetStatus, ApprovalDataAuthParam param) {
        TenantAuthDO tenantAuthDO = new TenantAuthDO();
        tenantAuthDO.setId(param.getId());
        tenantAuthDO.setStatus(targetStatus);
        tenantAuthDO.setModifyBy(currentUser.getId());
        tenantAuthDO.setModifyTime(LocalDateTime.now());
        tenantAuthMapper.updateById(tenantAuthDO);

        TenantAuthRecordDO tenantAuthRecordDO = new TenantAuthRecordDO();
        tenantAuthRecordDO.setAuthId(tenantAuthDO.getId());
        tenantAuthRecordDO.setChecker(currentUser.getId());
        tenantAuthRecordDO.setCheckerName(currentUser.getName());
        tenantAuthRecordDO.setPassRefuseReason(param.getPassRefuseReason());
        tenantAuthRecordDO.setCurrentStatus(currentStatus);
        tenantAuthRecordDO.setTargetStatus(targetStatus);
        tenantAuthRecordDO.setCreateTime(LocalDateTime.now());

        tenantAuthRecordMapper.insert(tenantAuthRecordDO);
    }
}
